#include "TextureManager.h"

#include "D3DUtility.h"

#pragma warning (disable : 4996)

TextureManager TextureManager::m_Instance;

TextureManager::TextureManager()
{
	m_Textures.clear();
	m_Device = NULL;
	m_Sprite = NULL;
}

TextureManager::~TextureManager()
{

}

TextureManager* TextureManager::GetInstance()
{
	return &m_Instance;
}

bool TextureManager::Initialize(LPDIRECT3DDEVICE9 device, LPD3DXSPRITE sprite)
{
	m_Device = device;
	m_Device->AddRef();

	m_Sprite = sprite;
	m_Sprite->AddRef();

	return ( m_Device && m_Sprite ? true : false );
}

void TextureManager::Shutdown()
{
	for(unsigned int i = 0; i < m_Textures.size(); i++)
	{
		m_Textures[i].refCount = 0;
		SRELEASE(m_Textures[i].texture);
		m_Textures[i].fileName[0] = '\0';
	}

	m_Textures.clear();
	SRELEASE(m_Sprite);
	SRELEASE(m_Device);
}

int TextureManager::LoadTeture(const char* fileName, DWORD colorKey)
{
	if( !fileName )
		return -1;

	int id = -1;

	for(unsigned int i = 0; i < m_Textures.size(); i++)
	{
		if( strcmp(fileName, m_Textures[i].fileName) == 0 )
		{
			m_Textures[i].refCount++;
			return i;
		}

		if( m_Textures[i].refCount == 0 )
		{
			id = i;
		}
	}

	if( id == -1 )
	{
		TEXTURE loaded;
		strcpy(loaded.fileName, fileName);
		HRESULT hr = 0;
		
		if( FAILED(hr = D3DXCreateTextureFromFileEx(m_Device, fileName, D3DX_DEFAULT_NONPOW2, 
			D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, 0,
			D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT,
			D3DX_DEFAULT, colorKey, 0, 0, &loaded.texture)) )
		{
			char szBuffer[256] = {0};
			sprintf(szBuffer, "Failed to create texture - %s", fileName);
			MessageBox(0, szBuffer, "Texture manager Error", MB_OK);
			return -1;
		}

		loaded.refCount = 1;
		D3DSURFACE_DESC d3dSurfDesc;
		memset(&d3dSurfDesc, 0, sizeof(d3dSurfDesc));
		loaded.texture->GetLevelDesc(0, &d3dSurfDesc);
		loaded.width = d3dSurfDesc.Width;
		loaded.height = d3dSurfDesc.Height;
		m_Textures.push_back(loaded);

		return (int)m_Textures.size() - 1;
	}
	else
	{
		SRELEASE(m_Textures[id].texture);
		strcpy(m_Textures[id].fileName, fileName);
		HRESULT hr = 0;
		
		if( FAILED(hr = D3DXCreateTextureFromFileEx(m_Device, m_Textures[id].fileName, D3DX_DEFAULT_NONPOW2, 
			D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, 0,
			D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT,
			D3DX_DEFAULT, colorKey, 0, 0, &m_Textures[id].texture)) )
		{
			char szBuffer[256] = {0};
			sprintf(szBuffer, "Failed to create texture - %s", fileName);
			MessageBox(0, szBuffer, "Texture manager Error", MB_OK);
			return -1;
		}

		D3DSURFACE_DESC d3dSurfDesc;
		memset(&d3dSurfDesc, 0, sizeof(d3dSurfDesc));
		m_Textures[id].texture->GetLevelDesc(0, &d3dSurfDesc);
		m_Textures[id].width = d3dSurfDesc.Width;
		m_Textures[id].height = d3dSurfDesc.Height;
		m_Textures[id].refCount = 1;

		return id;
	}

	return -1;
}

bool TextureManager::UnloadTexture(int id)
{
	if( id <= -1 && id >= (int)m_Textures.size() )
		return false;

	m_Textures[id].refCount--;
	if( m_Textures[id].refCount <= 0 )
	{
		SRELEASE(m_Textures[id].texture);
		m_Textures[id].fileName[0] = '\0';
		m_Textures[id].refCount = 0;
	}

	return true;
}

int TextureManager::GetTextureWidth(int id)
{
	if( id <= -1 && id >= (int)m_Textures.size() )
		return -1;
	return m_Textures[id].width;
}

int TextureManager::GetTextureHeight(int id)
{
	if( id <= -1 && id >= (int)m_Textures.size() )
		return -1;
	return m_Textures[id].height;
}

bool TextureManager::Draw(int id, int x, int y, float xScale, float yScale, 
	RECT *pSection, float rotCenterX, float rotCenterY, float rotation, DWORD color)
{
	if( id <= -1 && id >= (int)m_Textures.size() )
		return false;

	if( m_Textures[id].texture == NULL )
		return false;

	if( !m_Sprite )
		return false;

	D3DXMATRIX scale_mat;
	D3DXMATRIX rotation_mat;
	D3DXMATRIX translate_mat;
	D3DXMATRIX combined_mat;

	D3DXMatrixIdentity(&combined_mat);

	// Scale
	D3DXMatrixScaling(&scale_mat, xScale, yScale, 1.0f);
	combined_mat *= scale_mat;

	// Rotate
	D3DXMatrixTranslation(&translate_mat, -rotCenterX * xScale, -rotCenterY * yScale, 0.0f);
	combined_mat *= translate_mat;
	D3DXMatrixRotationZ(&rotation_mat, rotation);
	combined_mat *= rotation_mat;
	D3DXMatrixTranslation(&translate_mat, rotCenterX * xScale, rotCenterY * yScale, 0.0f);
	combined_mat *= translate_mat;

	// Translate
	D3DXMatrixTranslation(&translate_mat, (float)x, (float)y, 0.0f);
	combined_mat *= translate_mat;

	// Transform
	m_Sprite->SetTransform(&combined_mat);

	if( FAILED(m_Sprite->Draw(m_Textures[id].texture, pSection, NULL, NULL, color)) )
		DXERROR("Failed to draw the texture.");

	D3DXMatrixIdentity(&combined_mat);
	m_Sprite->SetTransform(&combined_mat);

	return true;
}

#pragma warning( default : 4996 )